﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace AhpilyServer
{
    /// <summary>
    /// 编码工具类
    /// </summary>
    public class EncodeTool
    {
        #region 粘包拆包
        /// <summary>
        /// 构造数据包 [包头+包尾]
        /// </summary>
        public static byte[] EncodePacket(byte[] data)
        {
            //内存流对象
            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    //先写入长度
                    bw.Write(data.Length);
                    //再写入数据
                    bw.Write(data);

                    byte[] byteArray = new byte[(int)ms.Length];
                    Buffer.BlockCopy(ms.GetBuffer(), 0, byteArray, 0, byteArray.Length);
                    return byteArray;
                }
            }
        }

        /// <summary>
        /// 解析数据包 从缓存中取出完整的数据包
        /// </summary>
        public static byte[] DecodePacket(ref List<byte> dataCache)
        {
            if (dataCache.Count < 4)
            {
                //throw new Exception("数据缓存长度不足4 不能构成一个完整的数据包");
                return null;
            }

            using (MemoryStream ms = new MemoryStream(dataCache.ToArray()))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    //读取包头 确认包尾长度
                    int length = br.ReadInt32();
                    //判断当前缓存中是否为完整的数据包
                    int dataRemainLength = (int)(ms.Length - ms.Position);
                    if (length > dataRemainLength)
                    {
                        //throw new Exception("数据长度不够包头约定的长度 不能构成一个完整的数据包");
                        return null;
                    }
                    //读取包尾
                    byte[] data = br.ReadBytes(length);
                    //更新数据包内容 去除已读取部分
                    dataCache.Clear();
                    dataCache.AddRange(br.ReadBytes(dataRemainLength));
                    return data;
                }
            }
        }
        #endregion

        #region 构造发送的SocketMessage类
        /// <summary>
        /// 把SocketMessage对象转换成字节数组发送出去
        /// </summary>
        public static byte[] EncodeMessage(SocketMessage message)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    bw.Write(message.OpCode);
                    bw.Write(message.SubCode);
                    //value不为空 转成字节数据存起来
                    if (message.Value != null)
                    {
                        byte[] valueBytes = EncodeObj(message.Value);
                        bw.Write(valueBytes);
                    }
                    byte[] data = new byte[ms.Length];
                    Buffer.BlockCopy(ms.GetBuffer(), 0, data, 0, data.Length);
                    return data;
                }
            }
        }
        /// <summary>
        /// 将接收到的字节数组 转换成SocketMessage对象
        /// </summary>
        public static SocketMessage DecodeMessage(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                using (BinaryReader br = new BinaryReader(ms))
                {
                    SocketMessage message = new SocketMessage
                    {
                        OpCode = br.ReadInt32(),
                        SubCode = br.ReadInt32()
                    };
                    //还有剩余字节 说明有value值 读出
                    if (ms.Length > ms.Position)
                    {
                        byte[] valueBytes = br.ReadBytes((int)(ms.Length - ms.Position));
                        object value = DecodeObj(valueBytes);
                        message.Value = value;
                    }
                    return message;
                }
            }
        }
        #endregion

        #region 把object类型转换成byte[]
        /// <summary>
        /// 序列化对象
        /// </summary>
        public static byte[] EncodeObj(object value)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(ms, value);
                byte[] valueBytes = new byte[ms.Length];
                Buffer.BlockCopy(ms.GetBuffer(), 0, valueBytes, 0, valueBytes.Length);
                return valueBytes;
            }
        }
        /// <summary>
        /// 反序列化
        /// </summary>
        public static object DecodeObj(byte[] valueBytes)
        {
            using (MemoryStream ms = new MemoryStream(valueBytes))
            {
                BinaryFormatter bf = new BinaryFormatter();
                object value = bf.Deserialize(ms);
                return value;
            }
        }
        #endregion 
    }
}
